# coding = utf-8
# File date: Hi_2022/1/6 21:13
# File_name: ID_main.py
from subprocess import run
from tkinter.ttk import Combobox, Sizegrip
from city_info import city
from tkinter import Tk, Frame, Label, Button, Listbox, Scrollbar, END
from MyBalloon import My_Balloon

city_dict = city


class ID_:
    def __init__(self, master):
        self.master = master

        # 创建两个基本frame,一个放基本信息选填,一个放生成的数据
        self.info_frame = Frame(self.master, cursor="hand2", relief="sunken", bd=1)
        self.data_frame = Frame(self.master)
        self.info_frame.place(relx=0.03, rely=0, relwidth=0.94, relheight=0.08)  # 区域信息控件
        self.data_frame.place(relx=0.03, rely=0.08, relwidth=0.94, relheight=0.94)  # 生成数据展示

        # 城市信息变量,默认西安未央
        self.id1_6 = None

        # 生日变量，默认20001111
        self.id7_14 = None

        # 生成按钮
        self.start_button = Button(self.info_frame, text="生 成", bg="Lavender", command=self.calculate)
        # a按钮提示气泡
        My_Balloon(self.master, self.start_button, "点击后生成两组数据\n左边为男性身份证,右侧为女性身份证。\n双击左键选中数据并复制。", fg="White")

        # 男左女右
        self.leabel_man = Label(self.data_frame, text="男", bg="LightYellow")
        self.leabel_woman = Label(self.data_frame, text="女", bg="Pink")

        # 数据列表
        scrollbar_left = Scrollbar(self.data_frame, orient="vertical")
        scrollbar_right = Scrollbar(self.data_frame, orient="vertical")
        self.dataleft = Listbox(self.data_frame, cursor="hand2", relief="sunken", bd=1, justify="center", yscrollcommand=scrollbar_left.set)
        self.dataright = Listbox(self.data_frame, cursor="hand2", relief="sunken", bd=1, justify="center", yscrollcommand=scrollbar_right.set)
        scrollbar_left.config(command=self.dataleft.yview)
        scrollbar_right.config(command=self.dataright.yview)

        # 绑定左键双击复制
        self.dataleft.bind("<Double-Button-1>", ID_.copy_str)
        self.dataright.bind("<Double-Button-1>", ID_.copy_str)

        # 布局
        self.leabel_man.place(relx=0, rely=0, relwidth=0.5, relheight=0.03)
        self.leabel_woman.place(relx=0.5, rely=0, relwidth=0.5, relheight=0.03)
        self.dataleft.place(relx=0, rely=0.03, relwidth=0.48, relheight=0.97)
        scrollbar_left.place(relx=0.48, rely=0.03, relwidth=0.02, relheight=0.97)
        self.dataright.place(relx=0.50, rely=0.03, relwidth=0.48, relheight=0.97)
        scrollbar_right.place(relx=0.98, rely=0.03, relwidth=0.02, relheight=0.97)

        self.main()

    def main(self):
        """运行所有方法"""
        self.area()
        self.birthday_sex()

    def area(self):
        """选择地区信息,并更新省市区对应的值"""
        # 默认城市列表信息
        province = ID_.return_city("86")  # 省
        citys = ID_.return_city("610000")  # 市
        district = ID_.return_city("610100")  # 区县

        # 省市区下拉框
        area_label = Label(self.info_frame, text="地区:")
        pro_box = Combobox(self.info_frame, state="readonly", values=province)
        city_box = Combobox(self.info_frame, state="readonly", values=citys)
        dis_box = Combobox(self.info_frame, state="readonly", values=district)

        # 默认值
        pro_box.current(26)  # 陕西
        city_box.current(0)  # 西安
        dis_box.current(4)  # 未央

        # 更新前六位
        self.id1_6 = dis_box.get().split("：")[1]

        # 发生改变时更新城市信息
        pro_box.bind("<<ComboboxSelected>>", lambda event: self.update_city(1, pro_box, city_box, dis_box))
        city_box.bind("<<ComboboxSelected>>", lambda event: self.update_city(2, pro_box, city_box, dis_box))
        dis_box.bind("<<ComboboxSelected>>", lambda event: self.update_city(3, pro_box, city_box, dis_box))

        # 地区布局
        area_label.place(relx=0, rely=0.08, relwidth=0.05, relheight=0.353)
        pro_box.place(relx=0.06, rely=0.08, relwidth=0.24, relheight=0.353)
        city_box.place(relx=0.3, rely=0.08, relwidth=0.27, relheight=0.353)
        dis_box.place(relx=0.57, rely=0.08, relwidth=0.27, relheight=0.353)
        self.start_button.place(relx=0.86, rely=0.08, relwidth=0.14, relheight=0.78)

    def birthday_sex(self):
        """更新3个生日下拉框"""
        birthday_leable = Label(self.info_frame, text="生日:")
        year_combox = Combobox(self.info_frame, state="readonly", values=list(range(2030, 1899, -1)))
        month_combox = Combobox(self.info_frame, state="readonly", values=list(range(1, 13, 1)))
        day_combox = Combobox(self.info_frame, state="readonly", values=list(range(1, 31, 1)))

        # 默认值
        year_combox.current(30)  # 2000
        month_combox.current(10)  # 11
        day_combox.current(10)  # 11

        # 当年月发生改变时，检查是否2月改变天数
        month_combox.bind("<<ComboboxSelected>>", lambda event: self.update_day(year_combox, month_combox, day_combox))
        year_combox.bind("<<ComboboxSelected>>", lambda event: self.update_day(year_combox, month_combox, day_combox))
        day_combox.bind("<<ComboboxSelected>>", lambda event: self.update_day(year_combox, month_combox, day_combox))

        # 更新生日变量
        self.id7_14 = f"{year_combox.get()}{month_combox.get()}{day_combox.get()}"

        # 生日布局
        birthday_leable.place(relx=0, rely=0.524, relwidth=0.05, relheight=0.353)
        year_combox.place(relx=0.06, rely=0.524, relwidth=0.24, relheight=0.353)
        month_combox.place(relx=0.3, rely=0.524, relwidth=0.27, relheight=0.353)
        day_combox.place(relx=0.57, rely=0.524, relwidth=0.27, relheight=0.353)

    def update_day(self, year_combox: Combobox, month_combox: Combobox, day_combox: Combobox):
        """计算月天数"""
        year = int(year_combox.get())
        month = int(month_combox.get())
        # print(type(year), type(month), year, month)
        if month == 2:
            if (year % 4 == 0 and year % 100 != 0) or (year % 4 == 0 and year % 100 == 0 and year % 400 == 0):  # 闰年29
                day_combox["values"] = list(range(1, 30, 1))
            else:  # 非闰年28
                day_combox["values"] = list(range(1, 29, 1))
        elif month in [1, 3, 5, 7, 8, 10, 12]:  # 31
            day_combox["values"] = list(range(1, 32, 1))
        else:  # 30
            day_combox["values"] = list(range(1, 31, 1))

        # 更新生日变量，并把小于10的给补充0
        self.id7_14 = f"{year_combox.get() if int(year_combox.get()) >= 10 else f'0{year_combox.get()}'}" \
                      f"{month_combox.get() if int(month_combox.get()) >= 10 else f'0{month_combox.get()}'}" \
                      f"{day_combox.get() if int(day_combox.get()) >= 10 else f'0{day_combox.get()}'}"
        # print(type(self.id7_14))

    @staticmethod
    def return_city(city_id: str):
        """返回city_id下所有 城市名-编号 列表"""
        return [f"{j}：{i}" for i, j in city_dict[city_id].items()]

    def update_city(self, updatetype, province_combox, citys_combox, district_combox):
        """改变时更新城市信息"""
        # 以：切割，取城市编号
        lam_a = lambda parameter: parameter.get().split("：")[1]

        # 1为省发生改变，2市，3区县
        if updatetype == 1:
            citys_combox["values"] = self.return_city(province_combox.get().split("：")[1])  # 更新城市列表
            citys_combox.current(0)  # 市更新后默认取第一个
            district_combox["values"] = self.return_city(citys_combox["values"][0].split("：")[1])
            district_combox.current(0)  # 区县更新后默认取第一个
        elif updatetype == 2:
            district_combox["values"] = self.return_city(citys_combox.get().split("：")[1])
            district_combox.current(0)  # 区县更新后默认取第一个
        self.id1_6 = lam_a(district_combox)

    def calculate(self):
        """计算身份证,"""
        # 重新生成先清除旧数据
        self.dataleft.delete(0, END)
        self.dataright.delete(0, END)
        for i in range(101, 1000, 1):  # 顺序码奇数分配给男性，偶数分配给女性。
            id18 = ID_.check_code(self.id1_6 + self.id7_14 + str(i))
            if i % 2 == 0:
                self.dataright.insert(END, f"{self.id1_6}{self.id7_14}{i}{id18}")
            else:
                self.dataleft.insert(END, f"{self.id1_6}{self.id7_14}{i}{id18}")

    # 计算校验码
    @staticmethod
    def check_code(id_number17):
        """
        1、将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为：7－9－10－5－8－4－2－1－6－3－7－9－10－5－8－4－2。
        2、将这17位数字和系数相乘的结果相加。
        3、用加出来和除以11，看余数是多少？
        4、余数只可能有0－1－2－3－4－5－6－7－8－9－10这11个数字。其分别对应的最后一位身份证的号码为1－0－X －9－8－7－6－5－4－3－2。（即余数0对应1，余数1对应0，余数2对应X）
        """
        coefficient = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
        sum_product = 0
        for i in range(17):
            product = int(id_number17[i]) * int(coefficient[i])
            sum_product += product
        # print('系数和对应位数乘法积和为%s' % sum_product)
        remainder = int(sum_product) % 11
        remainder = str(remainder)
        # print('转换前的校验码为%s' % remainder)

        # 转换表转换
        conversion_dictionary = {'0': '1', '1': '0', '2': 'X', '3': '9', '4': '8',
                                 '5': '7', '6': '6', '7': '5', '8': '4', '9': '3'}
        tran_table = str.maketrans(conversion_dictionary)
        if remainder == '10':
            remainder = '2'
        else:
            remainder = remainder.translate(tran_table)
        # print('转换后的校验码为%s' % remainder)
        return remainder

    @staticmethod
    def copy_str(event):
        """datas数据写入粘贴板"""
        data = event.widget.get(event.widget.curselection())
        print(data)
        run(r'ECHO %s|CLIP' % data, shell=True)


if __name__ == '__main__':
    root = Tk()
    root.title("身份证生成")
    win_w = root.winfo_screenwidth()
    win_h = root.winfo_screenheight()
    rootw = int(win_w * 0.28)
    rooth = int(win_h * 0.6)
    # 设置窗口长宽
    root.geometry(f"{rootw}x{rooth}+{(win_w - rootw) // 2}+{(win_h - rooth) // 2}")
    # root.resizable(False, False)  # 不可调整大小
    root.wm_attributes('-topmost', 1)  # 窗口置顶
    Sizegrip(root).pack(side="bottom", anchor="se")  # 尺寸手柄

    ID_(root)
    root.mainloop()
